<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>升级固件</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">  
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container" style="width: 80%">
   <h1>Mqtt远程固件升级</h1>
   <br>
   <br>
   <div class="row">
    <!-- 左侧 -->
    <div class="col-md-5">
      <div class="panel panel-primary">
        <div class="panel-heading">
          <h3 class="panel-title">加载固件</h3>
        </div>
        <div class="panel-body">
          <input style="width: 250;height: 60;font-size: 20px;" type="file" accept=".bin" value="upload" id="fileInput">
          <p id="fileInfo"></p>
        </div>
      </div>
      <div class="panel panel-primary">
        <div class="panel-heading">
          <h3 class="panel-title">整包大小设置(byte)</h3>
        </div>
        <div class="panel-body">
          <input type="text" id="packageSize" style="font-size: 18px;" value="1024">
          <button type="button" id="setPackageSizeBtn" class="btn btn-success">设置</button>
        </div>
      </div>
      <div class="panel panel-primary">
        <div class="panel-heading">
          <h3 class="panel-title">操作</h3>
        </div>
        <div class="panel-body">
          <button id='updateBtn' style="width: 150;height: 60;font-size: 28px;">更新固件</button>
        </div>
      </div>
    </div>
    <!-- 右侧 -->
    <div class="col-md-7">
      <div class="panel panel-primary">
        <div class="panel-heading">
          <h3 class="panel-title">消息区</h3>
        </div>
        <div class="panel-body">
          <!-- 清除消息 -->
          <button type="button" id="clearMsg" class="btn btn-warning">清除</button>
          <h4 id='msg' style="text-justify"></h4>
        </div>
      </div>
    </div>
 </div>
</div>
</body>
</html>
<script src='/scripts/jquery-3.4.0.min.js'></script>
<script src="/scripts/mqttws31.js"></script>
<script src="/common/fun.js"></script>
<script>
var _deviceid = getUrlParam('deviceid');  
var id = (new Date()).valueOf(); //ms时间戳，唯一话题标志
var packageSize=1024;//整包包字节数
var packageNum;//包数
var remainder;//最后一包字节数

var file;
var firmWareBuf;
var fileInput = document.getElementById("fileInput"),
     fileInfo = document.getElementById("fileInfo");

function  AnalysisPackage(){
  remainder = file.size%packageSize;
  if (remainder==0) {
      packageNum = (file.size-remainder)/packageSize;
  }
  else{
      packageNum = (file.size-remainder)/packageSize+1;
  }
  $("#msg").prepend(formatDate()+'-> 单包大小:'+packageSize+'byte<br /><br />');
  $("#msg").prepend(formatDate()+'-> 分包总数:'+packageNum+'个<br /><br />');
  $("#msg").prepend(formatDate()+'-> 剩余部分:'+remainder+'byte<br /><br />');
}
//这个函数的作用是把个位数的十位置0,凑成两位数，如：08 04 
var dateDigitToString = function (num) {  
    return num < 10 ? '0' + num : num;  
  };   
  function formatDate(){
  var currentDate = new Date(),  
    year = dateDigitToString(currentDate.getFullYear()),  
     month = dateDigitToString(currentDate.getMonth() + 1),//Date.getMonth()的返回值是0-11,所以要+1  
     date = dateDigitToString(currentDate.getDate()),  
     hour = dateDigitToString(currentDate.getHours()),  
     minute = dateDigitToString(currentDate.getMinutes()),  
     second = dateDigitToString(currentDate.getSeconds()),  
     formattedDateString = year + '年' + month + '月' + date + '日 ' + hour + ':' + minute + ':' + second;  
  return formattedDateString;   
}
//监听加载文件click事件
fileInput.addEventListener('click',function(){
  document.getElementById("fileInput").value='';
});

//监听加载文件change事件
fileInput.addEventListener('change',function(){

  //检查文件是否选择
  if(!fileInput.value){
    console.log('fileInput:',fileInput);
      // fileInfo.innerHTML = "请加载文件！";
      return;
  }
  
  //获取file的引用
  file = fileInput.files[0];
  console.log("file",file);
  AnalysisPackage();
  $("#msg").prepend(formatDate()+'-> 文件:'+file.name+'byte<br /><br />');
  $("#msg").prepend(formatDate()+'-> 大小:'+file.size+'byte<br /><br />');
                
  //将字符串转换成 Blob对象
	var blob = new Blob(['中文字符串'], {
    type: 'text/plain'
	});
	//将对象转换成 ArrayBuffer
	var reader = new FileReader();
	reader.readAsArrayBuffer(file);
	reader.onload = function (e) {
    console.info(reader.result);
    firmWareBuf = new Uint8Array(reader.result);
    console.info('firmWareBuf:',firmWareBuf); 
	}
});

/*************************MQTT****************************************/
var mqttclient;
var pubTopicCmd='device-'+_deviceid+'/updataFirmware/sever/cmd';
var pubTopicData='device-'+_deviceid+'/updataFirmware/sever/data';
var subTopic='device-'+_deviceid+'/updataFirmware/client';
var connect_clientId= Math.floor(Math.random() * 100000).toString();
// 连接mqtt服务器
// var options = 
// {
//     timeout: 3,
//     keepAliveInterval:60,
//     onSuccess:function()
//     {
//         //document.getElementById("status").innerHTML = "connected to server";
//         alert("connected to server");
//     },
//     onFailure:function(message)
//     {
//         //document.getElementById("status").innerHTML = "connect failed";
//         alert("connection failed to server");
//     }
// }
$(function() {
  var host = '47.102.150.235';    
  var port = '61623';
  var clientId = connect_clientId;
  var user = 'admin';
  var password = 'password';
  mqttclient = new Messaging.Client(host, Number(port), clientId);
  mqttclient.onConnect = onConnect;
  mqttclient.onMessageArrived = onMessageArrived;
  mqttclient.onConnectionLost = onConnectionLost;           

  mqttclient.connect({
    userName:user, 
    password:password, 
    onSuccess:onConnect, 
    onFailure:onFailure,
    timeout: 3, //连接超时时间
    keepAliveInterval:60
  }); 
  return false;
});  

//连接时订阅话题
var onConnect = function(frame) {
  $("#msg").prepend(formatDate()+'-> 已连接Mqtt！<br /><br />');
  $("#msg").prepend(formatDate()+'-> 已订阅话题:'+subTopic+'<br /><br />');
  mqttclient.subscribe(subTopic,{qos:2});
};  
//发生错误
function onFailure(failure) {
  $("#msg").prepend(formatDate()+'-> 连接MQTT服务器失败！<br /><br />');
  console.log("Mqtt:failure",failure.errorMessage);
}  
// 接收到消息
function onMessageArrived(message) {
  var obj = JSON.parse(message.payloadString);
  if ( obj.id!= id)
    return;
  
  $("#msg").prepend(formatDate()+'-> 收到话题类型:'+obj.messageType+'！<br /><br />');
  console.log('收到订阅话题：',message);
  console.log('JSON格式：',obj);
  if (obj.messageType=='get') {
    if (firmWareBuf==null) 
      return;
    //解析请求第几包数据
    var index = obj.package;
    //获取数据
    var buf;
    $("#msg").prepend(formatDate()+'-> 收到第'+index+'帧请求！<br /><br />');
    //余数为0时，全部整数提取
    if(remainder==0)
    {
        buf = firmWareBuf.slice(packageSize*(index-1),packageSize*index);
    } 
    else
    {
      //余数不为0时，前面整数提取，最后一帧取余数
      if (index<packageNum) {
        buf = firmWareBuf.slice(packageSize*(index-1),packageSize*index);
      }
      else if (index=packageNum) {
        buf = firmWareBuf.slice(packageSize*(index-1),packageSize*(index-1)+remainder);
      }
    }
    //发布
    publish(pubTopicData,buf);
    console.log('第'+index+'帧:',buf);
    $("#msg").prepend(formatDate()+'-> 已发送第'+index+'帧数据！<br /><br />');
  }
  if (obj.messageType=='feedback') {
    if (obj.resualt=='success') {
      $("#msg").prepend(formatDate()+'-> 固件升级成功！<br /><br />');
    }
    else {
      $("#msg").prepend(formatDate()+'-> 固件升级失败！<br /><br />');
    }
  }
}
// 连接断开时
function onConnectionLost(responseObject) {
  if (responseObject.errorCode !== 0) {
    console.log('连接断开：',mqttclient.clientId + ": " + responseObject.errorCode + "\n");
    $("#msg").prepend(formatDate()+'-> 连接断开！<br /><br />');
  }
}
// 发布话题方法
function publish(topic,text) {
if (text) {
    message = new Messaging.Message(text);
    message.destinationName = topic;
    mqttclient.send(message);
  }
  return false;
}

/*******************监控按钮***************************/
$("#updateBtn").click( function () {
  if (firmWareBuf==null) {
    alert('请加载文件');
    return;
  }
  AnalysisPackage();

  var jsonObj={
    'id':id.toString(),
    "messageType":"updataFirmware",
    "size": file.size, 
    "package": packageNum, 
    "remainder":remainder 
  };
  var str = JSON.stringify(jsonObj);
  console.log('json:',str);
  publish(pubTopicCmd,str);
  $("#msg").prepend(formatDate()+'-> str'+'<br /><br />');
  $("#msg").prepend(formatDate()+'-> 已经发送升级固件指令：'+str+'<br /><br />');
  $("#msg").prepend('<br />');
});
function checkRate(input) {
　var re = /^[0-9]+.?[0-9]*$/; //判断字符串是否为数字 //判断正整数 /^[1-9]+[0-9]*]*$/ 
　if (!re.test(input)) {
　　　return false;
　} 
  else{
    return true;
  }
}
$("#setPackageSizeBtn").click( function () {
  var value = $("input#packageSize").val();
  // 判断是否为数字
  if(checkRate(value))
  {
    // 判断是否符合范围
    if (value>0 && value<=2048) {
      packageSize = value;
      if (file!=null) {
        AnalysisPackage();
      }
      else{
        $("#msg").prepend(formatDate()+'-> 单包大小:'+packageSize+'byte<br /><br />');
      }
    }
    else{
      $("#msg").prepend(formatDate()+'-> 请输入1-2048之间的数值！<br /><br />');
    }
  }
  else
  {
    $("#msg").prepend(formatDate()+'-> 请输入数值！<br /><br />');
  }
});
// 清除消息区
$("#clearMsg").click( function () {
  $("#msg").empty();
});
</script>